package taper.controller.plc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;

import org.apache.log4j.Logger;


import db.DatabaseManager;
import db.EntityWrapper;
import db.entity.Coefficient;
import db.entity.TaperMap;
import db.entity.TaperValue;
import taper.controller.ComPort;
import taper.controller.MewtocolCommand;
import util.Activity;
import util.Convertor;
import util.ErrorMessage;
import util.PLCSend;
import util.PropertiesLoader;
import util.UnitConversion;

public class TaperAdjustProcessor {
	private static final Logger log = Logger.getLogger(TaperAdjustProcessor.class);
	public static ArrayBlockingQueue<TaperAverage> taperAverageQueue = new ArrayBlockingQueue(20);
	
	public void startAdjustTaper(){
		    new Thread(new Runnable()
		    {
		       public void run() {
		        while (true) {
		         
		        	adjustTaper();
		        	
		          try {
					Thread.sleep(PropertiesLoader.getTaperAdjustInterval());
					
				} catch (InterruptedException e) {
					log.error("TaperAdjustProcessor:startAdjustTaper",e);
				}
		         }
	     }
		    }).start();
	}
	
	public void adjustTaper() {
		while (taperAverageQueue.size() > 0)
			try {
				TaperAverage taperAverage = (TaperAverage) taperAverageQueue.take();
				double average = taperAverage.getTaperAverage();
				
				log.info("Adjust taper id = " + taperAverage.getTaperID()+" Taper average:"+average);

				DatabaseManager dm = new DatabaseManager();
				TaperMap taper = dm.getTaperMapByTaper(taperAverage.getTaperID());

				if(taper != null){
					if(taper.getLeftTaper().equalsIgnoreCase(taperAverage.getTaperID())){
							taperAverage.setLeft(true);
					}else if(taper.getRightTaper().equalsIgnoreCase(taperAverage.getTaperID())){
							taperAverage.setRight(true);
					}
				}else{
					ErrorMessage.displayError(ErrorMessage.WARNING_ERROR, true, "Invalid TaperID", taperAverage.getTaperID()+" is not a valid taper id");
					log.info(taperAverage.getTaperID()+" is not a valid taper id");
				}

				String stationName = taper.getStationName();
				
				float vacuum =  coefficientFormula(stationName , taperAverage);
                
				if (taperAverage.isLeft()) {
					updateDBTaper("L", stationName, vacuum, taperAverage.getLotID());
				} else if (taperAverage.isRight()) {
					updateDBTaper("R", stationName, vacuum, taperAverage.getLotID());
				}
				
			} catch (Exception e) {
				log.error("TaperAdjustProcessor:adjustTaper",e);
			}
	}

	public void updateDBTaper(String arm, String stationName, float value, String lotID) {
		String taperID = arm + stationName;

		//double averageValue = value;

		//value = UnitConversion.convertMicronsToInchesHg(value);

		DatabaseManager dm = new DatabaseManager();
		TaperValue taperValue = dm.getTaperValueByTaperId(taperID);

			double taperValueDouble = taperValue.getAdjustmentValue();
			double oriTaperValueDouble = taperValueDouble;
			taperValueDouble += value;

			if (taperValueDouble > PropertiesLoader.getVacuumUpperLimit()) {
				//String message = "Upper limit exceeded "+PropertiesLoader.getVacuumUpperLimit()+" : WCS adjusting " + taperID + " from value " + taperValueDouble+ " adjust to " + PropertiesLoader.getVacuumUpperLimit();
				
				//String malayMessage = "Melebehi tahap maksimum "+PropertiesLoader.getVacuumUpperLimit()+": WCS adjust " + taperID +" dari " +taperValueDouble +" tukar ke "+PropertiesLoader.getVacuumUpperLimit();
				String message = "Upper limit exceeded : Adjust" + taperID + " from value " + taperValueDouble + " to maksimum " + PropertiesLoader.getVacuumUpperLimit()+"Hg";
				String malayMessage = "Melebehi vacuum maksimum : Adjust " + taperID +" dari " +taperValueDouble +" tukar kepada vacuum maksimum "+PropertiesLoader.getVacuumUpperLimit()+"Hg";
				Activity.log(message, PropertiesLoader.getSystemUser(), "Adjustment had been limited to upper value "+PropertiesLoader.getVacuumUpperLimit());
				log.info("Taper value:"+taperValueDouble+" exceed limit:"+PropertiesLoader.getVacuumUpperLimit());
				taperValueDouble = PropertiesLoader.getVacuumUpperLimit();
				
				List<String> errMsg01 = new ArrayList<String>();
				errMsg01.add(message);
				errMsg01.add(malayMessage);
                ErrorMessage.displayError(ErrorMessage.WARNING_ERROR, true, "Taper Adjust Upper Limit Exceed", "Taper Adjust ", errMsg01);
			}

			if (taperValueDouble < PropertiesLoader.getVacuumLowerLimit()) {
//				String message = "Lower limit exceeded:"+PropertiesLoader.getVacuumLowerLimit()+" WCS adjusting " + taperID + " from value " + taperValueDouble + " adjust to " + PropertiesLoader.getVacuumLowerLimit();
//
//				String malayMessage = "Melebehi tahap minimum "+PropertiesLoader.getVacuumLowerLimit()+": WCS adjust " + taperID +" dari " +taperValueDouble +" tukar ke "+PropertiesLoader.getVacuumLowerLimit();
				String message = "Lower limit exceeded : Adjust" + taperID + " from value " + taperValueDouble + " to minimum " + PropertiesLoader.getVacuumLowerLimit()+"Hg";

				String malayMessage = "Melebehi vacuum minima : Adjust " + taperID +" dari " +taperValueDouble +" tukar kepada vacuum minima "+PropertiesLoader.getVacuumLowerLimit()+"Hg";

				Activity.log(message, PropertiesLoader.getSystemUser(), "Adjustment had been limited to lower value "+PropertiesLoader.getVacuumLowerLimit() + " by SYSTEM");
				log.info("Taper value:"+taperValueDouble+" lower then limit:"+PropertiesLoader.getVacuumLowerLimit());
				taperValueDouble = PropertiesLoader.getVacuumLowerLimit();

				List<String> errMsg01 = new ArrayList<String>();
				errMsg01.add(message);
				errMsg01.add(malayMessage);
                ErrorMessage.displayError(ErrorMessage.WARNING_ERROR, true, "Taper Adjust Lower Limit Exceed", "Taper Adjust ", errMsg01);
				
			}

			if (taperValueDouble < 0.0D) {
				taperValueDouble = 0.0F;
			}

			taperValue.setAdjustmentValue(taperValueDouble);
			EntityWrapper<TaperValue> db = new EntityWrapper<TaperValue>();
			db.merge(taperValue);
			db.commit();
			// Logging.log(new Date(), "Update Vacuum:" + stationName + "[" +
			// arm + "]-LOTID=" + lotID + ",average=" + averageValue +
			// " Adjust " + value + "=" + taperValueDouble, "SYSTEM",
			// "Data auto received from WCS");
			Activity.log("Update Vacuum:" + stationName + "[" + arm + "]-LOTID=" + lotID + ",Current Taper value=" + oriTaperValueDouble+" Adjust " + value + "=" + taperValueDouble, PropertiesLoader.getSystemUser(), "Data auto received from WCS");
			
			log.info("Adjust " + stationName + " arm: "+arm+" with value: " + taperValueDouble+". Current value:"+oriTaperValueDouble+" Adjustment value:"+value);
			PLCSend.updatePLCTaper(arm, stationName, taperValueDouble);
		//}

	}


	
	private float coefficientFormula(String stationName, TaperAverage taperAverage){
		
		DatabaseManager dm = new DatabaseManager();
		Coefficient coe = null;
		double coefficient = 0;
		
		if(taperAverage.isLeft())
			coe = dm.listCoefficientByStationArm(stationName, "L");
		else if (taperAverage.isRight())
			coe = dm.listCoefficientByStationArm(stationName, "R");
		
		//calculate the value of region
		double regionB = coe.getUcl();
		double regionC = coe.getUcl() * coe.getCPercentage();
		double regionD = 0;
		double regionE = coe.getLcl() * coe.getEPercentage();
		double regionF = coe.getLcl();
		
		log.info("Region B:"+regionB+" Region C:"+regionC+" Region D:"+regionD+" Region E:"+regionE+" Region F:"+regionF);
		
		double taperRegion = taperAverage.getTaperAverage() - coe.getTargetValue();
		
		log.info("taperRegion:"+taperRegion);
		
		//check the value fall into which region
		if (taperRegion > regionB){
			//fall in region A
			log.info("fall in region A");
			coefficient = coe.getKa();
		}else if (taperRegion > regionC && taperRegion <= regionB){
			//fall in region b
			log.info("fall in region B");
			coefficient = coe.getKb();
		}else if(taperRegion > regionD && taperRegion <= regionC){
			// fall in region c
			coefficient = coe.getKc();
			log.info("fall in region C");
		}else if(taperRegion <= regionD && taperRegion > regionE){
			// fall in region D
			coefficient = coe.getKd();
			log.info("fall in region D");
		}else if (taperRegion <= regionE && taperRegion > regionF){
			//fall in region E
			coefficient = coe.getKe();
			log.info("fall in region E");
		}else if(taperRegion < regionF){
			//fall in region F
			coefficient = coe.getKf();
			log.info("fall in region F");
		}
		
		float formula = (float) (taperRegion * coefficient);
		log.info("(Current taper - Target taper)* Coefficient for the region . ("+taperAverage.getTaperAverage()+" - "+coe.getTargetValue()+") * "+coefficient+"="+formula);
		return formula;
	}
	
	

}
